#include "gwbase/byte_array.h"

#include <borzoi.h>
#include <mpi.h>
#include <sstream>
#include <assert.h>

#include <gwbase/base/util.h>
#include "gwbase/base64.h"
#include "gwbase/encrypt/enc_rand.h"

std::string BigIntToDecimal(const BigInt &val) {
  char buf[256];
  mp_todecimal(const_cast<mp_int *>(&val.mp), buf);
  return buf;
}

namespace dicom {

std::string ByteArray::toRawStr() const {
  return std::string(this->begin(), this->end());
}

std::string ByteArray::toHexStr() const {
  std::string out;
  out.reserve(this->size() * 2 + 1);
  for (size_t i = 0; i < this->size(); ++i)
    out += StringPrintf("%02x", static_cast<int>(this->at(i)));

  return out;
}

ByteArray ByteArray::fromRawStr(const std::string &raw) {
  ByteArray out;
  const uint8_t *start = reinterpret_cast<const uint8_t *>(raw.c_str());
  out.insert(out.end(), start, start + raw.length());
  return out;
}

static uint8_t HexToInt(uint8_t ch) {
  if (ch >= 'a' && ch <= 'z') return static_cast<uint8_t>(ch - 'a' + 10);

  if (ch >= '0' && ch <= '9') return static_cast<uint8_t>(ch - '0');

  if (ch >= 'A' && ch <= 'Z') return static_cast<uint8_t>(ch - 'A' + 10);

  assert(false);
  return 0;
}

ByteArray ByteArray::fromHexStr(const std::string &hex) {
  assert(hex.size() % 2 == 0);
  ByteArray out;
  for (unsigned i = 0; i < hex.length(); i += 2) {
    uint8_t high = HexToInt(hex[i]);
    uint8_t low = HexToInt(hex[i + 1]);
    out.push_back(static_cast<uint8_t>((high << 4) | low));
  }
  return out;
}

std::string ByteArray::toBase64Str() const {
  return Base64Helper::Encode(*this);
}

std::string ByteArray::toUrlBase64Str() const {
  return UrlBase64Helper::Encode(*this);
}

std::string ByteArray::toDecimalStr() const {
  std::string hex_str = this->toHexStr();
  BigInt val = hexto_BigInt(hex_str);
  return BigIntToDecimal(val);
}

ByteArray ByteArray::genRandom(size_t size) {
  ByteArray bytes(size);
  EncGenRandom(&bytes[0], bytes.size());
  return bytes;
}
}
